package com.ruoyi.common.utils.bean;

import com.ruoyi.common.utils.date.TimeUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.Date;

public class ReflectionUtil {
	private static final Logger LOGGER = LoggerFactory.getLogger(ReflectionUtil.class);

	private ReflectionUtil() {
	}

	public static boolean isField(Class<?> clazz, String fieldName) {
		try {
			Field field = clazz.getDeclaredField(fieldName);
			return (field != null);
		} catch (Throwable th) {
			LOGGER.error("ReflectionUtil.getField() throwable", th);
		}
		return false;
	}

	public static <T> Object get(Class<T> clazz, T obj, String fieldName) {
		try {
			Field field = clazz.getDeclaredField(fieldName);
			field.setAccessible(true);
			Object value = field.get(obj);
			return value;
		} catch (Throwable th) {
			LOGGER.error("ReflectionUtil.getString() throwable", th);
			throw new IllegalStateException(th);
		}
	}

	public static Class<?> getFieldType(Class<?> clazz, String fieldName) {
		try {
			Field field = clazz.getDeclaredField(fieldName);
			field.setAccessible(true);
			return field.getType();
		} catch (Throwable th) {
			LOGGER.error("ReflectionUtil.getFieldType() throwable", th);
			throw new IllegalStateException(th);
		}
	}

	public static Field getFieldByType(Class<?> clazz, Class<?> fieldType) {
		Field[] fields = clazz.getDeclaredFields();
		if (ArrayUtils.isNotEmpty(fields)) {
			for (Field field : fields) {
				if (fieldType != null && fieldType.isAssignableFrom(field.getType())
						&& !Modifier.isStatic(field.getModifiers())) {
					return field;
				}
			}
		}
		return null;
	}

	public static <T> String getString(Class<T> clazz, T obj, String fieldName) {
		try {
			Field field = clazz.getDeclaredField(fieldName);
			field.setAccessible(true);
			Object value = field.get(obj);
			if (value == null) {
				return null;
			}
			if (value instanceof String) {
				String val = (String) value;
				return val;
			} else {
				return String.valueOf(value);
			}
		} catch (Throwable th) {
			LOGGER.error("ReflectionUtil.getString() throwable", th);
			throw new IllegalStateException(th);
		}
	}

	public static <T> Double getDouble(Class<T> clazz, T obj, String fieldName) {
		try {
			Field field = clazz.getDeclaredField(fieldName);
			field.setAccessible(true);
			Object value = field.get(obj);
			if (value instanceof Float) {
				Float val = (Float) value;
				return Double.valueOf(val);
			} else if (value instanceof Double) {
				Double val = (Double) value;
				return val;
			} else if (value instanceof BigDecimal) {
				BigDecimal val = (BigDecimal) value;
				return val.doubleValue();
			} else if (value instanceof String) {
				if (NumberUtils.isCreatable((String) value)) {
					double val = Double.parseDouble((String) value);
					return val;
				}
			}
			return null;
		} catch (Throwable th) {
			LOGGER.error("ReflectionUtil.getDouble() throwable", th);
			throw new IllegalStateException(th);
		}
	}

	public static <T> BigDecimal getBigDecimal(Class<T> clazz, T obj, String fieldName) {
		try {
			Field field = clazz.getDeclaredField(fieldName);
			field.setAccessible(true);
			Object value = field.get(obj);
			if (value instanceof Float) {
				Float val = (Float) value;
				return BigDecimal.valueOf(val);
			} else if (value instanceof Double) {
				Double val = (Double) value;
				return BigDecimal.valueOf(val);
			} else if (value instanceof BigDecimal) {
				BigDecimal val = (BigDecimal) value;
				return val;
			} else if (value instanceof String) {
				if (NumberUtils.isCreatable((String) value)) {
					BigDecimal val = new BigDecimal((String) value);
					return val;
				}
			}
			return null;
		} catch (Throwable th) {
			LOGGER.error("ReflectionUtil.getDouble() throwable", th);
			throw new IllegalStateException(th);
		}
	}

	public static <T> Integer getInteger(Class<T> clazz, T obj, String fieldName) {
		try {
			Field field = clazz.getDeclaredField(fieldName);
			field.setAccessible(true);
			Object value = field.get(obj);
			if (value instanceof Integer) {
				Integer val = (Integer) value;
				return val;
			} else if (value instanceof Long) {
				Long val = (Long) value;
				return val.intValue();
			} else if (value instanceof String) {
				if (NumberUtils.isCreatable((String) value)) {
					int val = Integer.parseInt((String) value);
					return val;
				}
			}
			throw new ReflectiveOperationException(fieldName + " type error");
		} catch (Throwable th) {
			LOGGER.error("ReflectionUtil.getInteger() throwable", th);
			throw new IllegalStateException(th);
		}
	}

	public static <T> Long getLong(Class<T> clazz, T obj, String fieldName) {
		try {
			Field field = clazz.getDeclaredField(fieldName);
			field.setAccessible(true);
			Object value = field.get(obj);
			if (value instanceof Integer) {
				Integer val = (Integer) value;
				return Long.valueOf(val);
			} else if (value instanceof Long) {
				Long val = (Long) value;
				return val;
			} else if (value instanceof String) {
				if (NumberUtils.isCreatable((String) value)) {
					long val = Long.parseLong((String) value);
					return val;
				}
			}
			throw new ReflectiveOperationException(fieldName + " type error");
		} catch (Throwable th) {
			LOGGER.error("ReflectionUtil.getLong() throwable", th);
			throw new IllegalStateException(th);
		}
	}

	public static <T> Date getDate(Class<T> clazz, T obj, String fieldName) {
		try {
			if (obj != null) {
				clazz = (Class<T>) obj.getClass();
			}
			Field field = clazz.getDeclaredField(fieldName);
			field.setAccessible(true);
			Object value = field.get(obj);
			if (value instanceof Date) {
				Date val = (Date) value;
				return val;
			} else if (value instanceof String) {
				Date val = TimeUtil.parseTime((String) value);
				if (val == null) {
					val = TimeUtil.parseDate((String) value);
				}
				return val;
			}
			throw new ReflectiveOperationException(fieldName + " type error");
		} catch (Throwable th) {
			LOGGER.error("ReflectionUtil.getDate() throwable", th);
			throw new IllegalStateException(th);
		}
	}

	public static <T> T getField(Class<?> clazz, Serializable obj, String fieldName, Class<T> fieldType) {
		try {
			Field field = clazz.getDeclaredField(fieldName);
			field.setAccessible(true);
			Object fieldVal = field.get(obj);
			if (fieldType.isAssignableFrom(field.getType())) {
				T val = (T) fieldVal;
				return val;
			}
			throw new ReflectiveOperationException(fieldName + " is not " + fieldType);
		} catch (Throwable th) {
			LOGGER.error("ReflectionUtil.getField() throwable", th);
			throw new IllegalStateException(th);
		}
	}

	public static <T> void setField(Class<?> clazz, Serializable obj, String fieldName, T fieldValue) {
		try {
			Field field = clazz.getDeclaredField(fieldName);
			field.setAccessible(true);
			Class<?> fieldType = field.getType();
			if (fieldType.isInstance(fieldValue)) {
				field.set(obj, fieldValue);
			}
		} catch (Throwable th) {
			LOGGER.error("ReflectionUtil.setField() throwable", th);
			throw new IllegalStateException(th);
		}
	}

	public static <T> void setFieldIfNull(Class<?> clazz, Serializable obj, String fieldName, T fieldValue) {
		try {
			Field field = clazz.getDeclaredField(fieldName);
			field.setAccessible(true);
			Class<?> fieldType = field.getType();
			if (fieldType.isInstance(fieldValue)) {
				Object value = field.get(obj);
				if (value == null) {
					field.set(obj, fieldValue);
				}
			}
		} catch (Throwable th) {
			LOGGER.error("ReflectionUtil.setField() throwable", th);
			throw new IllegalStateException(th);
		}
	}

	public static String[] getTypeNames(Class<?>[] types) {
		if (ArrayUtils.isNotEmpty(types)) {
			String[] paramsTypes = new String[types.length];
			for (int idx = 0; idx < types.length; idx++) {
				if (types[idx] != null) {
					paramsTypes[idx] = types[idx].getName();
				} else {
					paramsTypes[idx] = "Unknow";
				}
			}
			return paramsTypes;
		}
		return new String[0];
	}
}
